using System.Collections.Concurrent;

namespace MultiAgentsServer.Scripts.Services.DataModels;

public class UserCookieDataModel
{
    public enum HubConnectionClassEnum
    {
        Workflow = 0,
        UserSettings = 1,
    }

    private readonly ConcurrentDictionary<int, List<(string deviceSerialNumber, string sessionId)>> UserToCookies = [];
    private readonly ConcurrentDictionary<string, Dictionary<HubConnectionClassEnum, string>> CookieToConnections = [];

    public void AddCookie(string sessionId, int userId, string deviceSerialNumber)
    {
        if (UserToCookies.TryGetValue(userId, out List<(string deviceSerialNumber, string sessionId)>? cookieList))
        {
            int existingCookie = cookieList.FindIndex(c => c.deviceSerialNumber == deviceSerialNumber);
            if (existingCookie != -1)
            {
                cookieList[existingCookie] = (deviceSerialNumber, sessionId);
            }
            else
            {
                cookieList.Add((deviceSerialNumber, sessionId));
            }
        }
        else
        {
            UserToCookies[userId] = [(deviceSerialNumber, sessionId)];
        }
    }

    public void AddConnection(string sessionId, string connectId, int userId, HubConnectionClassEnum hubConnectionClass)
    {
        if (UserToCookies.TryGetValue(userId, out List<(string deviceSerialNumber, string sessionId)>? cookieList)
            && cookieList.Any(c => c.sessionId == sessionId))
        {
            if (CookieToConnections.TryGetValue(sessionId, out var connectionDict) == false)
            {
                connectionDict = [];
                CookieToConnections[sessionId] = connectionDict;
            }

            connectionDict[hubConnectionClass] = connectId;
        }
    }

    public List<string> GetConnectionsByUserId(int userId, HubConnectionClassEnum hubConnectionClass)
    {
        List<string> connectionsAtIndex = [];

        if (UserToCookies.TryGetValue(userId, out List<(string deviceSerialNumber, string sessionId)>? cookieList))
        {
            foreach (var (_, sessionId) in cookieList)
            {
                if (CookieToConnections.TryGetValue(sessionId, out var connectionDict)
                    && connectionDict.TryGetValue(hubConnectionClass, out string? connection))
                {
                    if (connection != null)
                    {
                        connectionsAtIndex.Add(connection);
                    }
                }
            }
        }

        return connectionsAtIndex;
    }

    public bool CheckUserAndSession(int userId, string sessionId)
    {
        if (UserToCookies.TryGetValue(userId, out List<(string deviceSerialNumber, string sessionId)>? cookieList))
        {
            return cookieList.Any(c => c.sessionId == sessionId);
        }
        return false;
    }

    public void RemoveSession(int userId, string sessionId)
    {
        if (UserToCookies.TryGetValue(userId, out List<(string deviceSerialNumber, string sessionId)>? cookieList))
        {
            var existingCookieIndex = cookieList.FindIndex(c => c.sessionId == sessionId);
            if (existingCookieIndex != -1)
            {
                cookieList.RemoveAt(existingCookieIndex);
            }
            if (cookieList.Count == 0)
            {
                UserToCookies.Remove(userId, out _);
            }
        }

        CookieToConnections.Remove(sessionId, out _);
    }

    public void RemoveConnectionByConnectionId(string connectionId)
    {
        foreach (var sessionEntry in CookieToConnections)
        {
            var sessionId = sessionEntry.Key;
            var connectionDict = sessionEntry.Value;

            if (connectionDict != null)
            {
                foreach (var connectionEntry in connectionDict)
                {
                    if (connectionEntry.Value == connectionId)
                    {
                        connectionDict.Remove(connectionEntry.Key);

                        if (connectionDict.Count == 0)
                        {
                            CookieToConnections.TryRemove(sessionId, out _);
                        }
                        return;
                    }
                }
            }
        }
    }
}